﻿using dotnet_ef_admin.Src.Common.Const;
using dotnet_ef_admin.Src.Models;
using dotnet_ef_admin.Src.Utilities;
using Microsoft.EntityFrameworkCore;

namespace dotnet_ef_admin.Src.Services;

public class RoleService(DbCtx context) : IRoleService {
    private readonly DbCtx _context = context;

    /// <summary>
    ///     异步创建角色并保存到数据库。
    /// </summary>
    /// <param name="role">要创建的角色对象。</param>
    /// <returns>创建的角色。</returns>
    public async Task<Role> CreateAsync(Role role) {
        // 查找是否已经存在同名角色
        var existing = await _context.Roles.FirstOrDefaultAsync(r => r.Name == role.Name);

        if (existing != null) throw new Exception("角色已经存在");

        // 创建新角色
        var newRole = new Role {
            Name = role.Name
        };

        _context.Roles.Add(newRole);
        await _context.SaveChangesAsync();

        return role;
    }


    /// <summary>
    ///     异步获取所有角色信息。
    /// </summary>
    /// <param name="request">获取角色的请求参数，包括关键词、页码和每页大小。</param>
    /// <returns>返回一个包含所有角色的集合和总数的结果对象。</returns>
    public async Task<GetAllRolesResult> FindAllAsync(GetAllRolesRequest request) {
        try {
            var queryWhere = _context.Roles
                .Where(r => string.IsNullOrEmpty(request.Keywords) || r.Name.Contains(request.Keywords));
            var total = await queryWhere.CountAsync();

            var rolesQuery = queryWhere.OrderByDescending(r => r.Id)
                .Skip(((request.PageNum ?? BasePageQuery.PageNum) - 1) * (request.PageSize ?? BasePageQuery.PageSize))
                .Take(request.PageSize ?? BasePageQuery.PageSize)
                .Select(r => new Role {
                    Id = r.Id,
                    Name = r.Name,
                    Status = r.Status,
                    Code = r.Code,
                    Sort = r.Sort,
                    CreateTime = r.CreateTime,
                    UpdateTime = r.UpdateTime
                });

            var list = await rolesQuery.ToListAsync();

            return new GetAllRolesResult {
                List = list,
                Total = total
            };
        } catch (Exception e) {
            throw new Exception($"查询角色列表错误: {e.Message}");
        }
    }

    /// <summary>
    ///     异步根据角色ID获取角色信息。
    /// </summary>
    /// <param name="id">角色ID。</param>
    /// <returns>匹配的角色，如果没有找到则返回null。</returns>
    public async Task<Role?> FindByIdAsync(int id) {
        return await _context.Roles.FindAsync(id);
    }

    /// <summary>
    ///     异步更新数据库中的现有角色。
    /// </summary>
    /// <param name="role">要更新的角色对象。</param>
    /// <returns>更新后的角色。</returns>
    public async Task<Role> UpdateAsync(Role role) {
        _context.Roles.Update(role);
        await _context.SaveChangesAsync();
        return role;
    }

    /// <summary>
    ///     异步从数据库中删除角色。
    /// </summary>
    /// <param name="id">要删除的角色的ID。</param>
    public async Task DeleteAsync(int id) {
        var role = await _context.Roles.FindAsync(id);
        if (role != null) {
            _context.Roles.Remove(role);
            await _context.SaveChangesAsync();
        }
    }

    /// <summary>
    ///     异步批量删除角色。
    /// </summary>
    /// <param name="ids">要删除角色的ID数组。</param>
    /// <returns>删除后的受影响行数。</returns>
    public async Task<int> DeleteManyAsync(int[] ids) {
        var rolesToDelete = await _context.Roles.Where(r => ids.Contains(r.Id)).ToListAsync();

        _context.Roles.RemoveRange(rolesToDelete);

        return await _context.SaveChangesAsync();
    }

    /// <summary>
    ///     根据角色ID异步查找角色信息
    /// </summary>
    /// <param name="id">角色ID</param>
    /// <returns>返回查找到的角色对象，如果找不到，返回null</returns>
    public async Task<Role?> FindFormAsync(int id) {
        // 从数据库中查询角色信息，只返回符合条件的第一个角色对象
        return await _context.Roles.Where(r => r.Id == id).Select(r => new Role {
            Id = r.Id,
            Name = r.Name,
            Code = r.Code,
            Status = r.Status,
            Sort = r.Sort,
            DataScope = r.DataScope
        }).FirstOrDefaultAsync();
    }

    /// <summary>
    ///     根据角色ID异步查找该角色关联的菜单ID列表
    /// </summary>
    /// <param name="id">角色ID</param>
    /// <returns>返回角色关联的菜单ID列表</returns>
    public async Task<List<int>> FindMenusAsync(int id) {
        // 从数据库中查询角色关联的菜单ID列表
        var menuIds = await _context.RolesOnMenus
            .Where(rom => rom.RoleId == id)
            .Select(rom => rom.MenuId)
            .ToListAsync();

        return menuIds;
    }

    /// <summary>
    ///     异步更新角色菜单ID
    /// </summary>
    /// <param name="id">角色ID</param>
    /// <param name="menuIds">菜单ID列表</param>
    /// <returns>任务</returns>
    public async Task UpdateMenusAsync(int id, List<int> menuIds) {
        // 开启数据库事务
        await using var transaction = await _context.Database.BeginTransactionAsync();
        try {
            // 确保角色和菜单记录存在
            var roleExists = await _context.Roles.AnyAsync(r => r.Id == id);
            var menusExist = await _context.Menus.Where(m => menuIds.Contains(m.Id)).CountAsync();

            if (!roleExists || menusExist != menuIds.Count)
                throw new InvalidOperationException("角色或菜单不存在。");


            // 删除指定角色所有的菜单权限记录
            // var rolesToDelete = await _context.RolesOnMenus.Where(r => r.RoleId == id).ToListAsync();
            // _context.RolesOnMenus.RemoveRange(rolesToDelete);
            // await _context.SaveChangesAsync();

            // 使用 N.EntityFrameworkCore.Extensions 进行批量删除
            await _context.RolesOnMenus
                .Where(r => r.RoleId == id)
                .ExecuteDeleteAsync();

            // 创建新的角色菜单记录集合
            var menusRecord = menuIds.Select(menuId => new RolesOnMenus {
                MenuId = menuId,
                RoleId = id
            }).ToList(); // 确保将结果转换为 List

            // 批量插入新的角色菜单记录
            // 这里使用标准的 EF Core 方法
            // _context.RolesOnMenus.AddRange(menusRecord);
            // await _context.SaveChangesAsync();
            // 使用 Z.EntityFrameworkCore.Extensions 批量插入
            await _context.BulkInsertAsync(menusRecord);

            // 提交事务
            await transaction.CommitAsync();
        } catch (Exception) {
            // 发生异常时回滚事务
            await transaction.RollbackAsync();
            throw;
        }
    }

    /// <summary>
    ///     异步获取角色选项列表。
    /// </summary>
    /// <returns>包含角色选项的列表。</returns>
    public async Task<List<TransformedItem>> FindOptionsAsync() {
        var roles = await _context.Roles
            .Select(r => new Role {
                Id = r.Id,
                Name = r.Name
            })
            .ToListAsync();
        return Utils.TransformToOption(roles.Cast<object>().ToList());
    }
}